package com.tuanzi.loan.business.service.common.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.tuanzi.loan.business.entity.common.CommRegionNew;
import com.tuanzi.loan.business.enums.RegionTreeEnum;
import com.tuanzi.loan.business.repository.common.CommRegionNewRepository;
import com.tuanzi.loan.business.service.common.CommRegionNewService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.service.CommonServiceImpl;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.retry.RetryException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author weibifeng 2018/03/12
 */
@Debug
@Service
@Transactional
@Retryable(value = { RetryException.class })
public class CommRegionNewServiceImpl extends CommonServiceImpl<CommRegionNew, Long> implements CommRegionNewService {

	@Autowired
	private CommRegionNewRepository commRegionNewRepository;

	@Override
	protected JpaRepository<CommRegionNew, Long> getRepository() {
		return commRegionNewRepository;
	}

	/**
	 * 将所有城市级联生成树节点
	 * 
	 * @return
	 */
	@Override
	public TreeNode generateTreeNode(String city, RegionTreeEnum regionTreeEnum) {
		final List<CommRegionNew> topRegionList = Lists.newArrayList();
		final Map<String/* parentId */, List<CommRegionNew>> subRegionMap = Maps.newHashMap();
		List<CommRegionNew> allRegionList = findAll();
		for (CommRegionNew region : allRegionList) {

			String parentId = region.getPid();
			if (StringUtils.isEmpty(parentId) || "0".equals(parentId)) { // 省
				topRegionList.add(region);
			} else if (region.getLevel() == 2) { // 市
				List<CommRegionNew> regionList = subRegionMap.get(parentId);
				if (regionList == null) {
					regionList = Lists.newArrayList();
				}
				regionList.add(region);
				subRegionMap.put(parentId, regionList);
			}
		}

		if (regionTreeEnum == RegionTreeEnum.RECEIPT) {
			Predicate<CommRegionNew> provinceFilter = p -> p.getName().contains("青海") || p.getName().contains("内蒙古") || p.getName().contains("西藏") || p.getName().contains("新疆");
			List<CommRegionNew> receiptProvinceList = topRegionList.stream().filter(provinceFilter).collect(Collectors.toList());
			return generateTreeNode(receiptProvinceList, subRegionMap, city);
		}

		return generateTreeNode(topRegionList, subRegionMap, city);
	}

	public TreeNode generateTreeNode(List<CommRegionNew> provinceRegionList, Map<String, List<CommRegionNew>> cityRegionMap, String cityStr) {
		Map<String, String> cityMap = getCityMap(cityStr); // 已选中城市map
		TreeNode root = new DefaultTreeNode("Root", null);
		root.setExpanded(true);

		for (CommRegionNew province : provinceRegionList) {
			TreeNode provinceNode = new DefaultTreeNode(province, root);
			List<CommRegionNew> cityList = cityRegionMap.get(String.valueOf(province.getId()));
			if (cityList == null) {
				if (cityMap.size() > 0 && cityMap.containsKey(province.getName())) {
					provinceNode.setSelected(true);
				}

				continue;
			}
			if (cityMap.size() > 0 && cityMap.containsKey(province.getName())) {
				provinceNode.setSelected(true);
			}
			for (CommRegionNew city : cityList) {
				TreeNode cityNode = new DefaultTreeNode(city, provinceNode);
				if (cityMap.size() > 0 && cityMap.containsKey(city.getName())) {
					cityNode.setSelected(true); // 标记已经选中的城市
				}
			}
		}
		return root;
	}

	/**
	 * 省份城市节点数组，转换成省份和城市字符串
	 * 
	 * @param proAndCityNodes
	 * @return
	 */
	public Map<String, String> treeNodesToString(TreeNode[] proAndCityNodes) {
		Map<String, String> regionMap = new HashMap<String, String>();
		if (proAndCityNodes == null || proAndCityNodes.length < 1) {
			return regionMap;
		}

		List<String> provinceList = new ArrayList<String>();
		StringBuffer citySbf = new StringBuffer();
		for (TreeNode node : proAndCityNodes) {
			CommRegionNew region = (CommRegionNew) node.getData();
			if (region.getLevel() == 2) {
				String province = ((CommRegionNew) node.getParent().getData()).getName();
				if (!provinceList.contains(province)) {
					provinceList.add(province);
				}
				citySbf.append(region.getName()).append(",");
			}
		}
		String provinceStr = listToString(provinceList);
		String cityStr = citySbf.deleteCharAt(citySbf.length() - 1).toString();
		regionMap.put("province", provinceStr);
		regionMap.put("city", cityStr);

		return regionMap;
	}

	private String listToString(List<String> list) {
		StringBuffer sbf = new StringBuffer();
		for (String str : list) {
			sbf.append(str).append(",");
		}
		return sbf.deleteCharAt(sbf.length() - 1).toString();
	}

	private Map<String, String> getCityMap(String citys) {
		Map<String, String> cityMap = new HashMap<String, String>();
		if (StringUtils.isNotEmpty(citys) && citys.length() > 0) {
			String[] cityArr = citys.split(",");
			for (String city : cityArr) {
				cityMap.put(city, city);
			}
		}
		return cityMap;
	}

	public List<String> extractProvinceFrom(TreeNode[] treeNodes) {
		if (ArrayUtils.isEmpty(treeNodes)) {
			return Lists.newArrayList();
		}
		return Stream.of(treeNodes).map(x -> (CommRegionNew) x.getData()).filter(x -> x.getLevel() == 1).map(CommRegionNew::getName).collect(Collectors.toList());
	}

	public List<String> extractCityFrom(TreeNode[] treeNodes) {
		if (ArrayUtils.isEmpty(treeNodes)) {
			return Lists.newArrayList();
		}
		return Stream.of(treeNodes).map(x -> (CommRegionNew) x.getData()).filter(x -> x.getLevel() == 2).map(CommRegionNew::getName).collect(Collectors.toList());
	}

}
